package core

import (
	"crypto/rand"
	"encoding/json"
	"fmt"
	"strconv"
	"time"

	"jlpay-sdk-go/pkg/jlpay/utils"
)

// SignVerifier 签名验证器接口
type SignVerifier interface {
	// Sign 签名
	Sign(method, uri string, body interface{}) (sign, timestamp, nonce string, err error)

	// Verify 验签
	Verify(method, uri, timestamp, nonce string, body interface{}, signature string) error
}

// DefaultSignVerifier 默认签名验证器
type DefaultSignVerifier struct {
	config *Config
}

// NewDefaultSignVerifier 创建默认签名验证器
func NewDefaultSignVerifier(config *Config) *DefaultSignVerifier {
	return &DefaultSignVerifier{
		config: config,
	}
}

// Sign 使用SM3WithSM2签名
func (v *DefaultSignVerifier) Sign(method, uri string, body interface{}) (sign, timestamp, nonce string, err error) {
	utils.Debugf("=== 开始签名过程 ===")

	// 获取当前时间戳（精确到秒）
	timestamp = strconv.FormatInt(time.Now().Unix(), 10)
	utils.Debugf("生成时间戳: %s", timestamp)

	// 生成随机字符串
	nonceBytes := make([]byte, 16)
	if _, err = rand.Read(nonceBytes); err != nil {
		return "", "", "", fmt.Errorf("生成随机数失败: %w", err)
	}
	nonce = utils.ToHexString(nonceBytes)
	utils.Debugf("生成nonce: %s", nonce)

	// 将请求体转为JSON字符串
	var bodyStr string
	if body != nil {
		// 检查是否是字符串类型（原始JSON字符串）
		if strBody, ok := body.(string); ok {
			bodyStr = strBody
		} else {
			// 对其他类型进行JSON序列化
			bodyJSON, err := json.Marshal(body)
			if err != nil {
				return "", "", "", fmt.Errorf("序列化请求体失败: %w", err)
			}
			bodyStr = string(bodyJSON)
		}
	}
	utils.Debugf("请求体字符串: %s", bodyStr)

	// 构造签名字符串
	signStr := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n", method, uri, timestamp, nonce, bodyStr)

	utils.Debugf("=== 签名字符串构造 ===")
	utils.Debugf("Method: %s", method)
	utils.Debugf("URI: %s", uri)
	utils.Debugf("Timestamp: %s", timestamp)
	utils.Debugf("Nonce: %s", nonce)
	utils.Debugf("Body: %s", bodyStr)
	utils.Debugf("完整签名字符串:\n%s", signStr)
	utils.Debugf("签名字符串长度: %d", len(signStr))
	utils.Debugf("签名字符串十六进制: %x", []byte(signStr))

	// 使用SM2签名
	utils.Debugf("开始SM2签名...")
	signBytes, err := utils.SM2Sign([]byte(signStr), v.config.PrivateKey)
	if err != nil {
		utils.Debugf("SM2签名失败: %v", err)
		return "", "", "", fmt.Errorf("SM2签名失败: %w", err)
	}

	signature := utils.ToBase64String(signBytes)
	utils.Debugf("签名成功，Base64签名: %s", signature)
	utils.Debugf("=== 签名过程结束 ===")

	return signature, timestamp, nonce, nil
}

// Verify 验证SM3WithSM2签名
func (v *DefaultSignVerifier) Verify(method, uri, timestamp, nonce string, body interface{}, signature string) error {
	// 将响应体转为JSON字符串
	var bodyStr string
	if body != nil {
		switch b := body.(type) {
		case string:
			bodyStr = b
		default:
			bodyJSON, err := json.Marshal(body)
			if err != nil {
				return fmt.Errorf("序列化响应体失败: %w", err)
			}
			bodyStr = string(bodyJSON)
		}
	}

	// 构造签名字符串
	signStr := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n", method, uri, timestamp, nonce, bodyStr)

	// 将签名Base64解码
	signBytes, err := utils.FromBase64String(signature)
	if err != nil {
		return fmt.Errorf("解码签名失败: %w", err)
	}

	// 验证签名
	ok, err := utils.SM2Verify([]byte(signStr), signBytes, v.config.JlpayPublicKey)
	if err != nil {
		return fmt.Errorf("验证签名失败: %w", err)
	}

	if !ok {
		return fmt.Errorf("签名验证不通过")
	}

	return nil
}
